/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.tewi.contexts;

import pl.tewi.types.InstancePorts;
import java.io.IOException;
import pl.tewi.types.ApplicationServerType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import pl.tewi.types.ApplicationDesc;
import pl.tewi.types.ModuleDesc;
import pl.tewi.utils.FileUtils;

/**
 * Klasa przechowująca wszystkie dane zebrane z adnotacji.
 * @author Marcin Kwapisz
 */
public class ApplicationServerContext {

    /**
     * baza ścieżki jndi zgodna z specyfikacją JEE6.
     */
    private static final String JEE_BASE_CONTEXT = "java:global/";
    /**
     * Separator ścieżki JNDI.
     */
    private static final String JNDI_SEPARATOR = "/";
    /**
     * Nazwa i jednocześnie identyfikator serwera testowego.
     */
    private String instanceName;
    /**
     * Typ serwera aplikacyjnego.
     */
    private ApplicationServerType applicationServerType;
    /**
     * Bazowy katalog w którym znajduje się instancja serwera aplikacyjnego.
     */
    private String instanceParentPath;
    /**
     * Nazwa hosta na którym pracuje serwer aplikacyjny.
     */
    private String hostName;
    /**
     * Konfiguracja portów instancji serwera apliakcyjnego.
     */
    private InstancePorts instancePorts;
    /**
     * Ścieżka w której testowany projekt się znajduje. W tym katalogu będą 
     * także umieszczane katalogi z konfiguracją domeny
     */
    private String projectPath;
    /**
     * zasoby do instalacji na serwerze.
     */
    private final ArrayList<String> resources = new ArrayList<String>();
    /**
     * Lista ścieżek do aplikacji do zainstalowania na serwerze aplikacyjnym.
     */
    private final Set<ApplicationDesc> applications = new HashSet<ApplicationDesc>();
    /**
     * Nazwa realmu bezpieczenstwa z którego będzie korzystała wdrożona aplikacja.
     */
    private String securityRealmName;
    /**
     * Lista uzytkowników którzy zostaną dadani do skonfiguraowanego realmu bezpieczeństwa.
     */
    private final ArrayList<String> users = new ArrayList<String>();

    /**
     * Pobiera nazwę instancji serwera aplikacyjnego.
     * @return nazwa instancji serwera
     */
    public String getInstanceName() {
        return instanceName;
    }

    /**
     * Ustawia nazwę instancji serwera aplikacyjnego.
     * @param targetName nazwa serwera aplikacyjnego
     */
    public void setInstanceName(final String targetName) {
        this.instanceName = targetName;
    }

    /**
     * Pobiera typ serwera aplikacyjnego.
     * @return typ serwera aplikacyjnego {@link ApplicationServerType}
     */
    public ApplicationServerType getApplicationServerType() {
        return applicationServerType;
    }

    /**
     * Ustawia w kontekście typ serwera aplikacyjnego.
     * @param applicationServerType typ serwera aplikacyjnego {@link ApplicationServerType}
     */
    public void setApplicationServerType(final ApplicationServerType applicationServerType) {
        this.applicationServerType = applicationServerType;
    }

    /**
     * Ustawia ścieżkę do katalogu zawierającego domenę serwera aplikacyjnego.
     * Wraz z nazwą domeny tworzy kompletną ścieżkę do instancji serwera aplikacyjengo
     * @param domainPath ścieżka do katalogu
     */
    public void setInstanceParentPath(final String domainPath) {
        instanceParentPath = domainPath;
    }

    /**
     * Pobiera ścieżkę do nadrzędnego katalogu instancji serwera aplikacyjnego.
     * @return ścieżka do katalogu
     */
    public String getInstanceParentPath() {
        return instanceParentPath;
    }

    /**
     * Metoda łączy {@link ApplicationServerContext#instanceParentPath} z 
     * {@link ApplicationServerContext#instanceName} i zwraca ścieżkę do 
     * katalogu instancji serwera aplikacyjnego.
     * @return bezwględna ścieżka do instancji serwera aplikacyjnego
     * @throws IOException gdy ścieżka jest nieprawidłowa
     */
    public String getInstanceRootPath() throws IOException {
        return FileUtils.joinPaths(instanceParentPath, instanceName);
    }

    /**
     * Pobiera nazwę hosta.
     * @return nazwa hosta
     */
    public String getHostName() {
        return hostName;
    }

    /**
     * Ustawia nazwę hosta.
     * @param instanceHostName nazwa hosta
     */
    public void setHostName(final String instanceHostName) {
        this.hostName = instanceHostName;
    }

    /**
     * Pobiera konfiguracjęportów instancji serwera aplikacyjnego.
     * @return porty komunikacyjne instancji serwera aplikacyjnego {@link InstancePorts}
     */
    public InstancePorts getInstancePorts() {
        return instancePorts;
    }

    /**
     * Ustawia konfigurację portów instancji serwera aplikacyjnego.
     * @param instancePorts konfiguracja portów {@link InstancePorts}
     */
    public void setInstancePorts(final InstancePorts instancePorts) {
        this.instancePorts = instancePorts;
    }

    /**
     * Pobiera ścieżkę do projektu z którego uruchamiane jest narzędzie.
     * @return ścieżka do katalogu
     */
    public String getProjectPath() {
        return projectPath;
    }

    /**
     * Ustawia ścieżkę do projektu z którego uruchamiane jest narzędzie.
     * @param projectPath ścieżka do katalogu
     */
    public void setProjectPath(final String projectPath) {
        this.projectPath = projectPath;
    }

    /**
     * Lista ścieżek do plików zawierających zasoby do instalacji na serwerze aplikacyjnym.
     * @return lista ścieżek do plików zasobów
     */
    public ArrayList<String> getResourceFiles() {
        return resources;
    }

    /**
     * Dodaje ścieżke do pliku zasobów.
     * @param filePath ścieżka do pliku
     * @return true w przypadku gdy udało się doadać ścieżkę do listy
     */
    public boolean addResourceFile(final String filePath) {
        return resources.add(filePath);
    }

    /**
     * Pobiera zbiór opisów aplikacji {@link ApplicationDesc}.
     * @return zbiór aplikacji
     */
    public Set<ApplicationDesc> getApplications() {
        return applications;
    }

    /**
     * Dodaje opis aplikacji do zbioru {@link ApplicationDesc}.
     * @param applicationDesc opis aplikacji
     * @return true jeżeli opis został do zbioru dodany
     */
    public boolean addApplication(final ApplicationDesc applicationDesc) {
        return applications.add(applicationDesc);
    }

    /**
     * Pobiera nazwę realmu bezpieczeństwa.
     * @return nazwa realmu bezpieczeństwa
     */
    public String getSecurityRealmName() {
        return securityRealmName;
    }

    /**
     * Ustawia nazwę realmu bezpieczeństwa.
     * @param securityRealmName nazwa realm-u
     */
    public void setSecurityRealmName(final String securityRealmName) {
        this.securityRealmName = securityRealmName;
    }

    /**
     * Dodaje użytkownika do listy użytkowników.
     * @param user nazwa użytkownika
     * @return true jeżeli dodanie użytkownika do listy się powiodło
     */
    public boolean addUser(final String user) {
        return users.add(user);
    }

    /**
     * Pobiera listę użytkowników do dodania do konfiguracji bezpieczeństwa 
     * serwera aplikacyjnego.
     * @return lista użytkowników
     */
    public ArrayList<String> getUsers() {
        return users;
    }

    @Override
    public String toString() {
        ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
        return builder.append(applicationServerType).append(instanceName).append(instanceParentPath).append(projectPath).append(applications).toString();
    }

    /**
     * <p>Oblicza konteksty wszystkich aplikacji skonfigurowanych dla danej 
     * instancji serwera aplikacyjnego, tzn dla tego kontekstu serwera 
     * aplikacyjnego.</p>
     * Każda aplikacja ma domyślnie jeden moduł, tak więc w takich przypadkach
     * zostaną zwrócone 2 konteksty bazowe np.:
     * <ul><li>java:global/appname/</li><li>java:global/appname/classes/</li></ul>
     * @return Kolekcja zakończonych znakiem "/" ścieżka kontekstu jndi do wyszukiwania komponentów EJB
     */
    public List<String> getJNDIBaseContextPath() {
        List<String> appContexts = new ArrayList<String>();
        StringBuilder appContext = new StringBuilder();
        for (ApplicationDesc desc : applications) {

            appContext.append(JEE_BASE_CONTEXT).append(desc.getName()).append(JNDI_SEPARATOR);
            String tempContext = appContext.toString();
            appContexts.add(tempContext);
            for (ModuleDesc moduleDesc : desc.getModules()) {
                appContext.append(moduleDesc.getName()).append(JNDI_SEPARATOR);
                appContexts.add(appContext.toString());
                appContext.delete(0, appContext.length());
                appContext.append(tempContext);
            }
            appContext.delete(0, appContext.length());
        }
        return appContexts;
    }
}

